package org.jsola.hr.common;

import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.Validator;
import org.apache.commons.lang.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegUtils {

    /**
     * 邮箱
     */
    public static final String EMAIL = "^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$";
    /**
     * 手机号码
     */
    public static final String PHONE = "^(1[3-9]([0-9]{9}))$";
    /**
     * 电话号码
     */
    public static final String PHONE_VALIDATE_CODE = "\"^8\\\\d{5}$\"";
    /**
     * 身份证
     */
    public static final String ID_CARD = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
    /**
     * 仅中文
     */
    public static final String CHINESE = "^[\\u4E00-\\u9FA5\\uF900-\\uFA2D]+$";
    /**
     * 整数
     */
    public static final String INTEGER = "^-?[1-9]\\d*$";
    /**
     * 数字
     */
    public static final String NUMBER = "^([+-]?)\\d*\\.?\\d+$";
    /**
     * 正整数
     */
    public static final String INTEGER_POS = "^[1-9]\\d*$";
    /**
     * 浮点数
     */
    public static final String FLOAT = "^([+-]?)\\d*\\.\\d+$";
    /**
     * 正浮点数
     */
    public static final String FLOAT_POS = "^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*$";
    /**
     * 是否为正整数数字，包括0（00，01非数字）
     */
    public static final String INTEGER_WITH_ZERO_POS = "^(([0-9])|([1-9]([0-9]+)))$";
    /**
     * 是否为整数数字，包括正、负整数，包括0（00，01非数字）
     */
    public static final String NUMBER_WITH_ZERO = "^((-)?(([0-9])|([1-9]([0-9]+))))$";
    /**
     * 是否为数字字符串
     */
    public static final String NUMBER_TEXT = "^([0-9]+)$";
    /**
     * 数字(整数、0、浮点数），可以判断是否金额，也可以是负数
     */
    public static final String NUMBER_ALL = "^((-)?(([0-9])|([1-9][0-9]+))(\\.([0-9]+))?)$";
    /**
     * QQ，5-14位
     */
    public static final String QQ = "^[1-9][0-9]{4,13}$";
    /**
     * IP地址
     */
    public static final String IP = "((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))";
    /**
     * 邮编
     */
    public static final String POST_CODE = "[1-9]\\d{5}(?!\\d)";
    /**
     * 普通日期
     */
    public static final String DATE = "^[1-9]\\d{3}-((0[1-9])|(1[0-2]))-((0[1-9])|([1-2][0-9])|(3[0-1]))$";
    /**
     * 复杂日期，不区分闰年的2月
     * 日期格式：2017-10-19
     * 或2017/10/19
     * 或2017.10.19
     * 或2017年10月19日
     * 最大31天的月份：(((01|03|05|07|08|10|12))-((0[1-9])|([1-2][0-9])|(3[0-1])))
     * 最大30天的月份：(((04|06|11))-((0[1-9])|([1-2][0-9])|(30)))
     * 最大29天的月份：(02-((0[1-9])|([1-2][0-9])))
     */
    public static final String DATE_COMPLEX = "^(([1-2]\\d{3})(-|/|.|年)((((01|03|05|07|08|10|12))(-|/|.|月)((0[1-9])|([1-2][0-9])|(3[0-1])))|(((04|06|11))(-|/|.|月)((0[1-9])|([1-2][0-9])|(30)))|(02-((0[1-9])|([1-2][0-9]))))(日)?)$";

    /**
     * 复杂的日期，区分闰年的2月
     * 这个日期校验能区分闰年的2月，格式如下：2017-10-19
     * （见：http://www.jb51.net/article/50905.htm）
     * ^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$
     */
    public static final String DATE_COMPLEX_LEAP_YEAR = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";

    /**
     * 正则表达式：验证港澳居民通行证 H/M + 10位或8位数字
     */
    public static final String REGEX_HK_CARD = "^[HMhm]{1}([0-9]{10}|[0-9]{8})$";

    /**
     * 正则表达式：验证台湾居民通行证 新版8位或1位英文+7位数字
     */
    public static final String REGEX_TW_CARD = "^(\\d{8}|^[a-zA-Z]{1}(\\d{7}))$";

    /**
     * 正则表达式校验,符合返回True
     *
     * @param regex   正则表达式
     * @param content 校验的内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isMatch(String regex, CharSequence content) {
        return Pattern.matches(regex, content);
    }


    /**
     * 校验手机号码
     *
     * @param mobile 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isMobile(String mobile) {
        boolean flag = false;
        if (null != mobile && !"".equals(mobile.trim()) && mobile.trim().length() == 11) {
            Pattern pattern = Pattern.compile(PHONE);
            Matcher matcher = pattern.matcher(mobile.trim());
            flag = matcher.matches();
        }
        return flag;
    }

    /**
     * 身份证
     *
     * @param idCard 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isIdCard(String idCard) {
        boolean flag = false;
        if (null != idCard && !"".equals(idCard.trim()) && idCard.trim().length() == 18) {
            Pattern pattern = Pattern.compile(ID_CARD);
            Matcher matcher = pattern.matcher(idCard.trim());
            flag = matcher.matches();
        }
        return flag;
    }

    /**
     * 身份证(包括港澳台)
     *
     * @param idCard 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isIdCardAllType(String idCard) {
        boolean flag = false;
        if (null != idCard && !"".equals(idCard.trim()) && idCard.trim().length() == 18) {
            Pattern pattern = Pattern.compile(ID_CARD);
            Matcher matcher = pattern.matcher(idCard.trim());
            flag = matcher.matches();
        }else if(!StringUtils.isEmpty(idCard)){
            if(idCard.length()==11 || idCard.length()==9){
                flag = true;
                String substring = idCard.substring(0,1);
                String substring1 = idCard.substring(1);
                if(!"H".equals(substring) && !"M".equals(substring)){
                    return false;
                }
                flag = Validator.isNumber(substring1);
            }else if(idCard.length()==8){
                flag = true;
                String substring = idCard.substring(0,1);
                String substring1 = idCard.substring(1);
                try {
                    Validator.validateWord(substring, "");
                } catch (ValidateException e) {
                    if(!Validator.isNumber(substring)){
                        return false;
                    }
                }
                flag = Validator.isNumber(substring1);
            }


        }
        return flag;
    }


    /**
     * 校验邮箱
     *
     * @param value 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isEmail(String value) {
        boolean flag = false;
        if (null != value && !"".equals(value.trim())) {
            Pattern pattern = Pattern.compile(EMAIL);
            Matcher matcher = pattern.matcher(value.trim());
            flag = matcher.matches();
        }
        return flag;
    }


    /**
     * 校验密码
     *
     * @param password 校验内容
     * @return 长度符合返回true，否则为false
     */
    public static boolean isPassword(String password) {
        boolean flag = false;
        if (null != password && !"".equals(password.trim())) {
            password = password.trim();
            if (password.length() >= 6 && password.length() <= 30) {
                return true;
            }
        }
        return flag;
    }


    /**
     * 校验手机验证码
     *
     * @param value 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isPhoneValidateCode(String value) {
        boolean flag = false;
        if (null != value && !"".equals(value.trim())) {
            Pattern pattern = Pattern.compile(PHONE_VALIDATE_CODE);
            Matcher matcher = pattern.matcher(value.trim());
            flag = matcher.matches();
        }
        return flag;
    }


    /**
     * 判断是否全部大写字母
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isUpperCase(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        String reg = "^[A-Z]$";
        return isMatch(reg, str);
    }


    /**
     * 判断是否全部小写字母
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isLowercase(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        String reg = "^[a-z]$";
        return isMatch(reg, str);
    }


    /**
     * 是否ip地址
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isIp(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(IP, str);
    }

    /**
     * 符合返回true，区分30、31天和闰年的2月份（最严格的校验），格式为2017-10-19
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isDate(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(DATE_COMPLEX_LEAP_YEAR, str);
    }


    /**
     * 简单日期校验，不那么严格
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isDateSimple(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(DATE, str);
    }


    /**
     * 区分30、31天，但没有区分闰年的2月份
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isDateComplex(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(DATE_COMPLEX, str);
    }


    /**
     * 判断是否为数字字符串，如0011，10101，01
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isNumberText(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(NUMBER_TEXT, str);
    }


    /**
     * 判断所有类型的数字，数字(整数、0、浮点数），可以判断是否金额，也可以是负数
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isNumberAll(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(NUMBER_ALL, str);
    }


    /**
     * 是否为正整数数字，包括0（00，01非数字）
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isIntegerWithZeroPos(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(INTEGER_WITH_ZERO_POS, str);
    }


    /**
     * 是否为整数，包括正、负整数，包括0（00，01非数字）
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isIntegerWithZero(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(NUMBER_WITH_ZERO, str);
    }


    /**
     * 符合返回true,QQ，5-14位
     *
     * @param str 校验内容
     * @return 符合正则表达式返回true，否则返回false
     */
    public static boolean isQQ(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return isMatch(QQ, str);
    }


    /**
     * 方法描述 获取字符串里面的数字，并拼接好返回
     *
     * @param str 校验内容
     * @author jp_cyl
     * @date 2020/2/25 11:47
     */
    public static String getPrefixNumberText(String str) {
        if (StringUtils.isBlank(str)) {
            return "0";
        }
        StringBuilder number = new StringBuilder("");

        String[] strArray = str.split("");

        for (String s : strArray) {
            if (org.jsola.hr.common.RegUtils.isNumberText(s)) {
                number.append(s);
            }
        }
        return number.toString();
    }

    /**
     * 校验港澳通行证
     *
     * @param HMNo 港澳通行证号
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isHMCard(String HMNo) {
        //校验非空
        if (StringUtils.isBlank(HMNo)) {
            return false;
        }
        return HMNo.matches(REGEX_HK_CARD);
    }

    /**
     * 校验台湾通行证
     * 规则 新版8位或18位数字,旧版10位数字 + 英文字母
     *
     * @param TWNo 台湾通行证号
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isTWCard(String TWNo) {
        //校验非空
        if (StringUtils.isBlank(TWNo)) {
            return false;
        }
        return TWNo.matches(REGEX_TW_CARD);
    }

    /**
     * 校验证件类型
     *
     * @return 1:居民身份证；2：港澳通行证；3：台湾通行证；null：无
     */
    public static Integer cardType(String cardNO) {
        if (isIdCard(cardNO)) {
            return 1;
        }
        if (isHMCard(cardNO)) {
            return 2;
        }
        if (isTWCard(cardNO)) {
            return 3;
        }
        return null;
    }

    /**
     * 校验银行卡卡号
     */
    public static boolean isBankCard(String bankCard) {
        if (bankCard == null) {
            return false;
        }
        if(bankCard.length() < 15 || bankCard.length() > 19) {
            return false;
        }
        char bit = getBankCardCheckCode(bankCard.substring(0, bankCard.length() - 1));
        if(bit == 'N'){
            return false;
        }
        return bankCard.charAt(bankCard.length() - 1) == bit;
    }

    /**
     * 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
     * @param nonCheckCodeBankCard
     * @return
     */
    public static char getBankCardCheckCode(String nonCheckCodeBankCard){
        if(nonCheckCodeBankCard == null || nonCheckCodeBankCard.trim().length() == 0
                || !nonCheckCodeBankCard.matches("\\d+")) {
            //如果传的不是数据返回N
            return 'N';
        }
        char[] chs = nonCheckCodeBankCard.trim().toCharArray();
        int luhmSum = 0;
        for(int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
            int k = chs[i] - '0';
            if(j % 2 == 0) {
                k *= 2;
                k = k / 10 + k % 10;
            }
            luhmSum += k;
        }
        return (luhmSum % 10 == 0) ? '0' : (char)((10 - luhmSum % 10) + '0');
    }

    public static void main(String[] args) {
//        System.out.println(isMobile("13430800244"));
//        System.out.println(isMobile("17730800244"));
//        System.out.println(isMobile("17630800244"));
//        System.out.println(isMobile("14730800244"));
//        System.out.println(isMobile("18330800244"));
//        System.out.println(isMobile("19330800244"));
//        System.out.println(isMobile("1333000244"));
        System.out.println(isBankCard("6214835663660411"));
    }
}
